#include "StdAfx.h"
#include <MyControls/TreeControl.h>
#include <MyFC/Glyph.h>

namespace My {

// ExpandableRow

ExpandableRow::ExpandableRow()
{
	m_Indent = 16;
	m_ButtonRect = CRect(0, 0, 0, 0);
}

void ExpandableRow::HandlePaint(CDC * pDC, const CRect & rClip)
{
	CBrush brush;
	brush.CreateSysColorBrush(COLOR_BTNFACE);
	pDC->FillRect(&rClip, &brush);
	CRect rClient = ClientRect();
	CPen pen(PS_SOLID, 1, GetSysColor(COLOR_BTNHILIGHT));
	pDC->SelectObject(&pen);
	pDC->MoveTo(rClient.left, rClient.bottom - 1);
	pDC->LineTo(rClient.right, rClient.bottom - 1);
	PaintCaption(pDC, rClient);
}

void ExpandableRow::HandleLeftDoubleClick(unsigned int flags, const CPoint & p)
{
	Row::HandleLeftDoubleClick(flags, p);
	if(CanExpand()) {
		if(IsExpanded())
			Collapse();
		else
			Expand();
	}
}

void ExpandableRow::HandleLeftDown(unsigned int flags, const CPoint & p)
{
	Row::HandleLeftDown(flags, p);
	if (CanExpand() && m_ButtonRect.PtInRect(p)) {
		if(IsExpanded())
			Collapse();
		else
			Expand();
	}
}

void ExpandableRow::PaintCaption(CDC * pDC, const CRect & rBounds)
{
	CRect rCaption(rBounds);

	My::Glyph btnUp; btnUp.Load("LISTBUTTONUP", "LISTBUTTONUPMASK");
	My::Glyph btnDown; btnDown.Load("LISTBUTTONDOWN", "LISTBUTTONDOWNMASK");

	rCaption.left =	btnUp.Width() + GetLevel() * m_Indent;

	if (!rCaption.IsRectEmpty()) {

		CRect rText(rCaption);
		rText.InflateRect(-4, 0);

		String caption = GetCaption();

		pDC->SetBkMode(TRANSPARENT);
		if (Enabled())
			pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
		else
			pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));

		pDC->DrawText(caption.c_str(), &rText, DT_SINGLELINE|DT_END_ELLIPSIS|DT_LEFT|DT_VCENTER);
		pDC->DrawText(caption.c_str(), &rText, DT_SINGLELINE|DT_END_ELLIPSIS|DT_VCENTER|DT_CALCRECT);

		rText = My::AlignRect(rCaption, rText, ALIGN_VCENTER);
		rText.InflateRect(2, 1);

//		if (IsActive() && GetGrid() != 0 && GetGrid()->HasFocus())
//			pDC->DrawFocusRect(&rText);

		if (CanExpand()) 
		{
			m_ButtonRect = rText;
			m_ButtonRect.right = rCaption.left;
			m_ButtonRect.left = m_ButtonRect.right - btnUp.Width() + 2;
			if (IsExpanded())
				btnDown.Draw(pDC, m_ButtonRect);
			else
				btnUp.Draw(pDC, m_ButtonRect);
		}
	}
}

// TreeRow

TreeRow::TreeRow() :
	m_pParentRow(0), m_Expanded(false)
{
}

bool TreeRow::IsEmpty() const
{
	return m_Children.empty();
}

My::Size TreeRow::GetChildCount() const
{
	return m_Children.size();
}

TreeRow & TreeRow::GetChild(My::Size i) const
{
	assert(i < m_Children.size());
	return * m_Children[i];
}

void TreeRow::Insert(My::Size pos, TreeRow * rows[], My::Size count)
{
	if (count == 0)
		return;
	assert(pos <= m_Children.size());
	
	m_Children.insert(m_Children.begin() + pos, rows, rows + count);
	
	for (My::Size i = pos; i < pos + count; ++i)
		m_Children[i]->m_pParentRow = this;

	if (Visible() && m_Expanded && GetList() != 0) {
		My::Size n = 0, i, p;
		for (i = pos; i < pos + count; ++i)
			n += m_Children[i]->CountRows();
		std::vector<Row *> rows(n);
		p = 0;
		for (i = pos; i < pos + count; ++i)
			p = m_Children[i]->EnumerateRows(&rows[0], p);
		My::Size last = m_Children.empty() ? 0 : 
			pos == 0 ? 0 : m_Children[pos - 1]->GetIndex() + m_Children[pos - 1]->CountRows();
		p = pos + count < m_Children.size() ? 
			m_Children[pos + count]->GetIndex() : last;
		GetList()->Insert(p, &rows[0], rows.size());
	}
}

void TreeRow::Remove(My::Size pos, My::Size count)
{
	if (count == 0)
		return;
	assert(pos + count <= m_Children.size());
	My::Size i;
	if (Visible() && m_Expanded && GetList() != 0) {
		My::Size n = 0;
		for (i = pos; i < pos + count; ++i)
			n += m_Children[i]->CountRows();
		GetList()->Remove(m_Children[pos]->GetIndex(), n);
	}
	for (i = pos; i < pos + count; ++i)
		m_Children[i]->m_pParentRow = 0;
	m_Children.erase(m_Children.begin() + pos, m_Children.begin() + pos + count);
}

void TreeRow::Clear()
{
	Collapse();
	m_Children.clear();
}

bool TreeRow::CanExpand() const
{
	return GetChildCount() != 0;
}

bool TreeRow::IsExpanded() const
{
	return m_Expanded;
}

void TreeRow::Expand()
{
	if (!m_Expanded) {
		m_Expanded = true;
		if (Visible() && GetList() != 0) {
			Invalidate();
			My::Size count = CountRows(false);
			if (count == 0)
				return;
			std::vector<Row *> rows(count);
			EnumerateRows(&rows[0], 0, false);
			GetList()->Insert(GetIndex() + 1, &rows[0], rows.size());
		}
	}
}

void TreeRow::Collapse()
{
	if (m_Expanded) {
		if (GetList() != 0) {
			Invalidate();
			GetList()->Remove(GetIndex() + 1, CountRows(false));
		}
		m_Expanded = false;
	}
}

My::Size TreeRow::GetLevel() const
{
	return GetParentRow() == 0 ? 
		0 : GetParentRow()->GetLevel() + 1;
}

My::Size TreeRow::CountRows(bool countSelf) const
{
	My::Size count = countSelf ? 1 : 0;
	if (m_Expanded) {
		for (My::Size i = 0; i < GetChildCount(); ++i)
			count += GetChild(i).CountRows();
	}
	return count;
}

My::Size TreeRow::EnumerateRows(Row * rows[], My::Size pos, bool enumSelf)
{
	if (enumSelf)
		rows[pos++] = this;
	if (m_Expanded) {
		for (My::Size i = 0; i < GetChildCount(); ++i)
			pos = GetChild(i).EnumerateRows(rows, pos);
	}
	return pos;
}

void TreeRow::SetVisible(bool on)
{

}

// Tree

Tree::Tree(ScrollBox & box) :
	List(box)
{
}

bool Tree::IsEmpty() const
{
	return m_Rows.empty();
}

My::Size Tree::GetRowCount() const
{
	return m_Rows.size();
}

TreeRow & Tree::GetRow(My::Size i) const
{
	return * m_Rows[i];
}

void Tree::Insert(My::Size pos, TreeRow * rows[], My::Size count)
{
	if (count == 0)
		return;
	assert(pos <= m_Rows.size());
	m_Rows.insert(m_Rows.begin() + pos, rows, rows + count);
	{
		My::Size n = 0, i, p;
		for (i = pos; i < pos + count; ++i)
			n += m_Rows[i]->CountRows();
		std::vector<Row *> rows(n);
		p = 0;
		for (i = pos; i < pos + count; ++i)
			p = m_Rows[i]->EnumerateRows(&rows[0], p);
		My::Size last = m_Rows.empty() ? 0 : 
			pos == 0 ? 0 : m_Rows[pos - 1]->GetIndex() + m_Rows[pos - 1]->CountRows();
		p = pos + count < m_Rows.size() ? 
				m_Rows[pos + count]->GetIndex() : last;
		List::Insert(p, &rows[0], rows.size());
	}
}

void Tree::Remove(My::Size pos, My::Size count)
{
	if (count == 0)
		return;
	assert(pos + count <= m_Rows.size());
	My::Size n = 0, i;
	for (i = pos; i < pos + count; ++i)
		n += m_Rows[i]->CountRows();
	List::Remove(m_Rows[pos]->GetIndex(), n);
	m_Rows.erase(m_Rows.begin() + pos, m_Rows.begin() + pos + count);
}

void Tree::Clear()
{
	List::Clear();
	m_Rows.clear();
}

} // My